from pyglet.window import mouse
from widget import Widget
from container import DynamicContainer, BasicContainer
from layout import BasicLayout
from buttons import BasicButton
import view



 

class VerticalDragButton(BasicContainer):

    def __init__(self, area, *args, **kwargs):
        BasicContainer.__init__(self, child=None, *args, **kwargs)

        self.area = area
        self.layout = self.area.child

        self._update_height()
        self._update_pos()
        
        self.connect('drag', self.scroll, mouse.LEFT)
        self.register_fg(view.BeveledOutlay)
    
    def _update_height(self):

        if self.layout.height > self.area.height:
            self.height = int(round(self.usable_height * self.area_ratio))
        elif self.area.height > self.layout.height:
            self.height = int(round(self.usable_height / self.area_ratio))

    def _update_pos(self):

            height = self.layout.top - self.area.top
            if self.area.height > self.layout.height:
                height *= -1

            pos = int(round(self.topstop - height / self.ratio))
            dy = pos - self.top
            BasicContainer.move_y(self, dy)


    def scroll(self, dx, dy):
        self.move_y(dy)

    @property
    def topstop(self):
        return self._parent.button_up.bottom - 1
    
    @property
    def bottomstop(self):
        return self._parent.button_down.top + 1

    @property
    def usable_height(self):
        return self.topstop - self.bottomstop

    @property
    def area_ratio(self):
        try:
            return self.area.height / float(self.layout.height)
        except ZeroDivisionError:
            return 1

    @property
    def ratio(self):
        try:
            if self.layout.height > self.area.height:
                return self.layout.height / float(self.usable_height)
            elif self.area.height > self.layout.height:
                return self.layout.height / float(self.height)
        
        except ZeroDivisionError:
            return 1

    def move_y(self, dy):
        if self.top + dy > self.topstop:
            dy -= (self.top + dy) - self.topstop

        elif self.bottom + dy < self.bottomstop:
            dy -= (self.bottom + dy) - self.bottomstop
       
        self._parent.scroll(0, dy * self.ratio)

        BasicContainer.move_y(self, dy)



class VerticalScrollBar(BasicLayout):

    def __init__(self, area, increment=10, *args, **kwargs):
        BasicLayout.__init__(self, *args, **kwargs)
        self._increment = increment

        self.area = area
        self.layout = self.area.child

        self.button_up = BasicButton(left=self.left + 1,
                                top=self.top - 1,
                                width=self.width - 2,
                                height=self.width - 2)
        self.button_up.connect('click', self._scroll_up, mouse.LEFT)

        self.button_down = BasicButton(left=self.left + 1,
                                  bottom=self.bottom + 2,
                                  width=self.width - 2,
                                  height=self.width - 2)
        self.button_down.connect('click', self._scroll_down, mouse.LEFT)

        self.drag_button = VerticalDragButton(self.area,
                                              parent=self,
                                              width=self.width - 2,
                                              left=self.left + 1)

        self.add_children([self.button_up,
                           self.button_down,
                           self.drag_button])
                                              
        self.register_fg(view.BeveledInlay)
        self.connect('scroll', self.drag_button.scroll)

    def _scroll_up(self):
        self.drag_button.scroll(0, self._increment)

    def _scroll_down(self):
        self.drag_button.scroll(0, self._increment * -1)

    def scroll(self, dx, dy):
        if self.area.height > self.layout.height:
            self.area.move_child(0, dy)
        else:
            self.area.move_child(0, dy * -1)


    def get_width(self):
        return BasicLayout.get_width(self)

    def set_width(self, width):
        BasicLayout.set_width(self, width)
        
        if width > 2:
            for child in self.children:

                child.width = width - 2
                child.left = self.left + 1
        
        elif width <= 2:
            for child in self.children:

                child.width = 0
    width = property(get_width, set_width)


    def get_height(self):
        return BasicLayout.get_height(self)

    def set_height(self, height):
        BasicLayout.set_height(self, height)
        
        if height > 2 * self.width:

            self.button_up.top = self.top - 1
            self.button_down.bottom = self.bottom + 1

            self.drag_button._update_height()
            self.drag_button._update_pos()
    height = property(get_height, set_height)


class HorizontalDragButton(BasicContainer):
    
    def __init__(self, area, *args, **kwargs):
        BasicContainer.__init__(self, *args, **kwargs)

        self.area = area
        self.layout = self.area.child

        self._update_width()
        self._update_pos()
        
        self.connect('drag', self.scroll, mouse.LEFT)
        self.register_fg(view.BeveledOutlay)
    
    def _update_width(self):

        if self.layout.width > self.area.width:
            self.width = int(round(self.usable_width * self.area_ratio))
        elif self.area.width > self.layout.width:
            self.width = int(round(self.usable_width / self.area_ratio))

    def _update_pos(self):
        width = self.layout.right - self.area.right
        if self.area.width > self.layout.width:
            width *= -1
        pos = int(round(self.rightstop - width / self.ratio))
        dx = pos - self.right
        BasicContainer.move_x(self, dx)


    def scroll(self, dx, dy):
        self.move_x(dx)

    @property
    def rightstop(self):
        return self._parent.button_right.left - 1
    
    @property
    def leftstop(self):
        return self._parent.button_left.right + 1

    @property
    def usable_width(self):
        return self.rightstop - self.leftstop

    @property
    def area_ratio(self):
        try:
            return self.area.width / float(self.layout.width)
        except ZeroDivisionError:
            return 1

    @property
    def ratio(self):
        try:
            if self.layout.width > self.area.width:
                return self.layout.width / float(self.usable_width)
            elif self.area.width > self.layout.width:
                return self.layout.width / float(self.width)
        
        except ZeroDivisionError:
            return 1


    def move_x(self, dx):
        if self.right + dx > self.rightstop:
            dx -= (self.right + dx) - self.rightstop

        elif self.left + dx < self.leftstop:
            dx -= (self.left + dx) - self.leftstop
       
        self._parent.scroll(dx * self.ratio, 0)
        BasicContainer.move_x(self, dx)



class HorizontalScrollBar(BasicLayout):

    def __init__(self, area, increment=10, *args, **kwargs):
        BasicLayout.__init__(self, *args, **kwargs)
        self._increment = increment

        self.area = area
        self.layout = self.area.child

        self.button_right = BasicButton(bottom=self.bottom + 1,
                                   right=self.right - 1,
                                   height=self.height -2,
                                   width=self.height - 2)
        self.button_right.connect('click', self._scroll_right, mouse.LEFT)

        self.button_left = BasicButton(bottom=self.bottom + 1,
                                  left=self.left + 1,
                                  height=self.height - 2,
                                  width=self.height - 2)
        self.button_left.connect('click', self._scroll_left, mouse.LEFT)

        self.drag_button = HorizontalDragButton(self.area,
                                                parent=self,
                                                height=self.height - 2,
                                                bottom=self.bottom + 1)

        self.add_children([self.button_right,
                           self.button_left,
                           self.drag_button])
                                              
        self.register_fg(view.BeveledInlay)
        self.connect('scroll', self.drag_button.scroll)

    def _scroll_right(self):
        self.drag_button.scroll(self._increment, 0)

    def _scroll_left(self):
        self.drag_button.scroll(self._increment * -1, 0)

    def scroll(self, dx, dy):
        if self.area.width > self.layout.width:
            self.area.move_child(dx, 0)
        else:
            self.area.move_child(dx * -1, 0)


    def get_height(self):
        return BasicLayout.get_height(self)

    def set_height(self, height):
        BasicLayout.set_height(self, height)
        
        if height > 2:
            for child in self.children:

                child.height = height - 2
                child.bottom = self.bottom + 1
        
        elif height <= 2:
            for child in self.children:

                child.height = 0
    height = property(get_height, set_height)


    def get_width(self):
        return BasicLayout.get_width(self)

    def set_width(self, width):
        BasicLayout.set_width(self, width)
        
        if width > 2 * self.height:

            self.button_right.right = self.right - 1
            self.button_left.left = self.left + 1

            self.drag_button._update_width()
            self.drag_button._update_pos()
    width = property(get_width, set_width)


class ScrollArea(BasicLayout):

    def __init__(self, child, increment=20,
                 add_vertical_scrollbar='ondemand',
                 vertical_scrollbar_pos='right',
                 vertical_scrollbar_width=20,
                 add_horizontal_scrollbar='ondemand',
                 horizontal_scrollbar_pos='bottom',
                 horizontal_scrollbar_height=20,
                 area_stick='topleft',
                 *args, **kwargs):

        BasicLayout.__init__(self, *args, **kwargs)
        
        self.layout = child
        self.area = DynamicContainer(child=child, left=self.left, 
                         width=self.width, bottom=self.bottom, 
                         height=self.height, stick=area_stick)

        BasicLayout.add_child(self, self.area)
        self._increment = increment

        self._add_vertical_scrollbar = add_vertical_scrollbar
        self._vertical_scrollbar_pos = vertical_scrollbar_pos
        self._vertical_scrollbar_width = vertical_scrollbar_width

        self._add_horizontal_scrollbar = add_horizontal_scrollbar
        self._horizontal_scrollbar_pos = horizontal_scrollbar_pos
        self._horizontal_scrollbar_height = horizontal_scrollbar_height

        self.vertical_scrollbar = None
        self.horizontal_scrollbar = None

        self.add_vertical_scrollbar()
        self.add_horizontal_scrollbar()


    def add_vertical_scrollbar(self):
        if self.vertical_scrollbar or\
           self._add_vertical_scrollbar == 'never' or\
           (self._add_vertical_scrollbar == 'ondemand' and\
            self.area.height == self.layout.height):

            return

        elif self._add_vertical_scrollbar in ('ondemand', 'always'):
            area_h_stick = self.area.xstick
            
            if self.horizontal_scrollbar:
                hsh_stick = self.horizontal_scrollbar.xstick

            if self._vertical_scrollbar_pos == 'right':
                self.area.xstick = 'left'
                left = self.right - self._vertical_scrollbar_width

                if self.horizontal_scrollbar:
                    self.horizontal_scrollbar.xstick = 'left'

            elif self._vertical_scrollbar_pos == 'left':
                self.area.xstick = 'right'
                left = self.left

                if self.horizontal_scrollbar:
                    self.horizontal_scrollbar.xstick = 'right'

            self.area.width -= self._vertical_scrollbar_width
            self.area.xstick = area_h_stick

            self.area.connect('drag', self._scroll, mouse.MIDDLE)
            self.area.connect('scroll', self._scroll)

            height = self.height
            bottom = self.bottom
            if self.horizontal_scrollbar:
                
                self.horizontal_scrollbar.width -= \
                        self._vertical_scrollbar_width
                self.horizontal_scrollbar.xstick = hsh_stick

                height = self.height - self._horizontal_scrollbar_height
                if self._horizontal_scrollbar_pos == 'bottom':
                    bottom = self.bottom + self._horizontal_scrollbar_height


            _s = VerticalScrollBar(self.area,
                                   self._increment,
                                   left=left,
                                   width=self._vertical_scrollbar_width,
                                   bottom=bottom,
                                   height=height)
            
            self.vertical_scrollbar = _s
            BasicLayout.add_child(self, _s)


    def _scroll(self, dx, dy):
        if self.vertical_scrollbar:
            self.vertical_scrollbar.drag_button.move_y(dy)

        if self.horizontal_scrollbar:
            self.horizontal_scrollbar.drag_button.move_x(dx)


    def add_horizontal_scrollbar(self):
        if self.horizontal_scrollbar or\
           self._add_horizontal_scrollbar == 'never' or\
           (self._add_horizontal_scrollbar == 'ondemand' and\
            self.area.width == self.layout.width):

            return

        elif self._add_horizontal_scrollbar in ('ondemand', 'always'):
            area_v_stick = self.area.ystick
            
            if self.vertical_scrollbar:
                vsv_stick = self.vertical_scrollbar.ystick

            if self._horizontal_scrollbar_pos == 'top':
                self.area.ystick = 'bottom'
                bottom = self.top - self._horizontal_scrollbar_height

                if self.vertical_scrollbar:
                    self.vertical_scrollbar.ystick = 'bottom'

            elif self._horizontal_scrollbar_pos == 'bottom':
                self.area.ystick = 'top'
                bottom = self.bottom

                if self.vertical_scrollbar:
                    self.vertical_scrollbar.ystick = 'top'

            self.area.height -= self._horizontal_scrollbar_height
            self.area.ystick = area_v_stick

            width = self.width
            left = self.left
            if self.vertical_scrollbar:
                
                self.vertical_scrollbar.height -= \
                        self._horizontal_scrollbar_height
                self.vertical_scrollbar.ystick = vsv_stick

                width = self.width - self._vertical_scrollbar_width
                if self._vertical_scrollbar_pos == 'left':
                    left = self.left + self._vertical_scrollbar_width

            _s = HorizontalScrollBar(self.area,
                                     self._increment,
                                     left=left,
                                     width=width,
                                     bottom=bottom,
                                     height=self._horizontal_scrollbar_height)
            
            self.horizontal_scrollbar = _s
            BasicLayout.add_child(self, _s)


    def remove_vertical_scrollbar(self):

        if self._add_vertical_scrollbar == 'ondemand' and\
           self.area.height == self.layout.height and\
           self.vertical_scrollbar:

            self.remove_child(child=self.vertical_scrollbar)
            area_h_stick = self.area.xstick

            if self.horizontal_scrollbar:
                hsh_stick = self.horizontal_scrollbar.xstick

            if self._vertical_scrollbar_pos == 'left':
                self.area.xstick = 'right'

                if self.horizontal_scrollbar:
                    self.horizontal_scrollbar.xstick = 'right'


            elif self._vertical_scrollbar_pos == 'right':
                self.area.xstick = 'left'

                if self.horizontal_scrollbar:
                    self.horizontal_scrollbar.xstick = 'left'

            self.area.width += self._vertical_scrollbar_width
            self.area.xstick = area_h_stick

            if self.horizontal_scrollbar:
                self.horizontal_scrollbar.width += \
                        self._vertical_scrollbar_width
                self.horizontal_scrollbar.xstick = hsh_stick


    def remove_horizontal_scrollbar(self):

        if self._add_horizontal_scrollbar == 'ondemand' and\
           self.area.width == self.layout.width and\
           self.horizontal_scrollbar:

            self.remove_child(child=self.horizontal_scrollbar)
            area_v_stick = self.area.ystick

            if self.vertical_scrollbar:
                vsv_stick = self.vertical_scrollbar.ystick

            if self._horizontal_scrollbar_pos == 'bottom':
                self.area.ystick = 'top'

                if self.vertical_scrollbar:
                    self.vertical_scrollbar.ystick = 'top'

            elif self._horizontal_scrollbar_pos == 'top':
                self.area.xstick = 'bottom'

                if self.vertical_scrollbar:
                    self.vertical_scrollbar.ystick = 'bottom'

            self.area.height += self._horizontal_scrollbar_height
            self.area.ystick = area_v_stick

            if self.vertical_scrollbar:
                self.vertical_scrollbar.height +=\
                        self._horizontal_scrollbar_height
                self.vertical_scrollbar.ystick = vsv_stick


    def get_width(self):
        return BasicLayout.get_width(self)

    def set_width(self, width):
        dw = width - self.width

        if self.xstick == 'left':

            if self.vertical_scrollbar and\
               self._vertical_scrollbar_pos == 'right':

                self.vertical_scrollbar.move_x(dw)


            if self.horizontal_scrollbar:
                hsh_stick = self.horizontal_scrollbar.xstick
                self.horizontal_scrollbar.xstick = 'left'

            area_h_stick = self.area.xstick
            self.area.xstick = 'left'


        elif self.xstick == 'right':

            if self.vertical_scrollbar and\
               self._vertical_scrollbar_pos == 'left':

                self.vertical_scrollbar.move_x(dw)

            if self.horizontal_scrollbar:
                hsh_stick = self.horizontal_scrollbar.xstick
                self.horizontal_scrollbar.xstick = 'right'

            area_h_stick = self.area.xstick
            self.area.xstick = 'right'

        self.area.width += dw
        self.area.xstick = area_h_stick
        
        if self.horizontal_scrollbar:
            self.horizontal_scrollbar.width += dw
            self.horizontal_scrollbar.xstick = hsh_stick

        BasicLayout.set_width(self, width)
    width = property(get_width, set_width)


    def get_height(self):
        return BasicLayout.get_height(self)

    def set_height(self, height):
        dh = height - self.height

        if self.ystick == 'bottom':

            if self.horizontal_scrollbar and\
               self._horizontal_scrollbar_pos == 'top':

                self.horizontal_scrollbar.move_y(dh)


            if self.vertical_scrollbar:
                vsv_stick = self.vertical_scrollbar.ystick
                self.vertical_scrollbar.ystick = 'bottom'

            area_v_stick = self.area.ystick
            self.area.ystick = 'bottom'


        elif self.ystick == 'top':

            if self.horizonal_scrollbar and\
               self._horizontal_scrollbar_pos == 'bottom':

                self.horizontal_scrollbar.move_y(dh)

            if self.vertical_scrollbar:
                vsv_stick = self.vertical_scrollbar.ystick
                self.vertical_scrollbar.ystick = 'top'

            area_v_stick = self.area.ystick
            self.area.ystick = 'top'

        self.area.height += dh
        self.area.ystick = area_v_stick
        
        if self.vertical_scrollbar:
            self.vertical_scrollbar.height += dh
            self.vertical_scrollbar.ystick = vsv_stick

        BasicLayout.set_height(self, height)
    height = property(get_height, set_height)


    def draw(self, rect=None):
        self.add_vertical_scrollbar()
        self.add_horizontal_scrollbar()
        self.remove_vertical_scrollbar()
        self.remove_horizontal_scrollbar()

        BasicLayout.draw(self, rect)


    def add_child(self, child):
        self.layout.add_child(child)

    def remove_child(self, child=None, nmb=None):
        self.layout.remove_child(child, nmb)

    def insert_child(self, nmb, child):
        self.layout.insert_child(nmb, child)
